//
//  UninitializedMemory.cpp
//  sad
//
//  Created by Christopher Kemsley on 2/26/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include <string>

#include "SystemCDefinitions.hpp"

#include "Settings.hpp"
#include "Exception.hpp"
#include "BusInterface.hpp"

#include "ModuleFactory.hpp"
#include "PubSub.hpp"
#include "Codec.hpp"

#include "Log.hpp"




struct UninitializedMemorySettings : public Settings
{
	unsigned	baseAddress ;
	unsigned	length ;
	std::string	busSlaveName ;
	
	UninitializedMemorySettings ( std::string const & name )
	:	Settings(name)
	,	baseAddress(0)
	,	busSlaveName()
		{
		add ( "baseAddress" , baseAddress ) ;
		add ( "length" , length ) ;
		add ( "slaveName" , busSlaveName ) ;
		}
	
	
	virtual void		validate ()
		{
		if ( busSlaveName.size() == 0 )
			ThrowException ( "UninitializedMemorySettings" , "busSlaveName has zero-length" , __FILE__,__LINE__ ) ;
		if ( length == 0 )
			ThrowException ( "UninitializedMemorySettings" , "length has zero-length" , __FILE__,__LINE__ ) ;
		}
} ;





struct UninitializedMemory : public ConfiguredModel<UninitializedMemorySettings>
{
	Bus::Word	*	mBuffer ;
	
	sc_port < Bus::SlaveInterface >	bus ;
	
	
	
	SC_HAS_PROCESS(UninitializedMemory) ;
	
	UninitializedMemory ( ModelVariant const & name )
	:	ConfiguredModel<UninitializedMemorySettings> ( name )
	,	mBuffer(new Bus::Word [mConfig.length])
	,	bus()
		{
		Subscription < Bus::SlaveInterface >	bus_	( mConfig.busSlaveName ) ;
		bindPortToInterface ( &bus , bus_ ) ;
		
		
		SC_THREAD ( loop ) ;
		}
	virtual ~UninitializedMemory ()
		{
		delete [] mBuffer ;
		}
	
	
	
	void	loop ()
		{
		try
			{
			while ( 1 )
				{
				Bus::Request	request ;
				
				Log::states("UninitializedMemory") << "Starting long wait cycle" ;
				
				while ( 1 )
					{
					Log::states("UninitializedMemory") << "Waiting for request" ;
					
					bus -> waitForNewRequest ( request ) ;
					
					Log::states("UninitializedMemory") << "Got request: " << request ;
					
					request . baseAddress -= mConfig.baseAddress ;
					
					if ( request.baseAddress < mConfig.length )
						if ( request.baseAddress+request.blockLength <= mConfig.length )
							{
							bus -> acknowledgeRequest() ;
							break ;
							}
					}
				
				Log::states("UninitializedMemory") << "Processing request: " << request ;
				
				
				unsigned	here	=	request.baseAddress ;
				unsigned	end		=	here + request.blockLength ;
				Bus::Word	word ;
				
				if ( request.operation == Bus::kOperationWrite )
					{
					while ( here < end )
						{
						Log::error("UninitializedMemory") << "Beginning read" ;
						bus -> readWord ( word ) ;
						Log::error("UninitializedMemory") << "Ending read" ;
						mBuffer [here++] = word ;
						}
					}
				else
					{
					while ( here < end )
						{
						word = mBuffer [here++] ;
						bus -> writeWord ( word ) ;
						}
					}
				}
			}
		catch ( Exception & e )
			{
			AddExceptionTrace ( e , "StaticMemoryController" , "An exception occurred in the loop" , __FILE__,__LINE__ ) ;
			Log::logException(e) ;
			}
		}
} ;





TypedModuleMaker<UninitializedMemory>	_UninitializedMemory ( "bus.memory.uninitialized" ) ;
